package logic.impl;

import java.io.File;
import java.io.FileInputStream;
import java.util.Iterator;
import java.util.Properties;
import java.util.Vector;

import util.LevenshteinDistance;

import model.AddressWrapper;
import model.VCardWrapper;

/**
 * 
 * resolver:
 * if prename & lastname is missing trying to extract them from email addr
 *
 */
public class ResolverNameFromEmail extends LogicElementBaseClass {
	
	private Properties prenames;
	private Properties names;
	private int maxLevenshteinDistanceForPrename;
	
	@Override
	public void init(Properties resolverProperties) {
		super.init(resolverProperties);
		
		prenames = new Properties();
		names = new Properties();
		maxLevenshteinDistanceForPrename = 3;
		
		if(resolverProperties.containsKey("ResolverNameFromEmail.PathMappingsNames")) {
			try {
				String paths = resolverProperties.getProperty("ResolverNameFromEmail.PathMappingsNames");
				String mappingPaths[] = paths.split(";");
				
				for(int i = 0; i < mappingPaths.length; i++) {
					log.info("loading name list from:" + mappingPaths[i]);
					Properties prop = new Properties();
					prop.load(new FileInputStream(new File(mappingPaths[i])));
					
					Iterator iter = prop.keySet().iterator();
					while(iter.hasNext()) {
						String key = (String) iter.next();
						names.put(key.toLowerCase(), prop.get(key));
					}
					
				}
			} catch (Exception exc) {
				log.error(exc);
				
			}
		}
		
		if(resolverProperties.containsKey("ResolverNameFromEmail.PathMappingsPrenames")) {
			try {
				String paths = resolverProperties.getProperty("ResolverNameFromEmail.PathMappingsPrenames");
				String mappingPaths[] = paths.split(";");
				
				for(int i = 0; i < mappingPaths.length; i++) {
					log.info("loading prename list from:" + mappingPaths[i]);
					Properties prop = new Properties();
					prop.load(new FileInputStream(new File(mappingPaths[i])));
					
					Iterator iter = prop.keySet().iterator();
					while(iter.hasNext()) {
						String key = (String) iter.next();
						prenames.put(key.toLowerCase(), prop.get(key));
					}		
				}				
			} catch (Exception exc) {
				log.error(exc);
			}
		}		

		if(resolverProperties.containsKey("ResolverNameFromEmail.MAXLDist_Prename")) {
			try {
				maxLevenshteinDistanceForPrename = new Integer(
						resolverProperties.getProperty(
								"ResolverNameFromEmail.MAXLDist_Prename"))
				.intValue();
				log.info("set maxLevenshteinDistanceForPrename to:" + maxLevenshteinDistanceForPrename);
			} catch (Exception exc) {
				log.error(exc);
			}
		}			
	}

	public void performResolving() {

		Vector <VCardWrapper>addressCards = this.getAddressBook().getAddressCards();
		for(int i = 0; i < addressCards.size(); i++) {
			VCardWrapper myCard = addressCards.get(i);
			
			if(myCard.existsEmail()) {
				boolean resolvePrename = false;
				boolean resolveLastname = false;
				
				if(myCard.existsPreName() == false) resolvePrename = true;
				if(myCard.existsLastName() == false) resolveLastname = true;
				
				/**
				 * email given, prename or lastname missing
				 */
				if(resolvePrename || resolveLastname) {
					
					/**
					 * extract account name from mailaddress:
					 * extract 'abc' from 'abc@xyz.com'
					 */
					String mailSplits[] = myCard.getEmail().split("@");
					if(mailSplits.length != 2) return;
					String mailAccountName = mailSplits[0];
					
					/**
					 * pattern: prename.lastname | lastname.prename
					 */
					String nameSplits[] = mailAccountName.split("\\.");
					if(nameSplits.length == 2) {
						if(performDoubleResolving(myCard, nameSplits[0], nameSplits[1]) == false)
							performDoubleResolving(myCard, nameSplits[1], nameSplits[0]);
						continue;
					}
					
					/**
					 * pattern: prename_lastname | lastname_prename
					 */
					nameSplits = mailAccountName.split("_");
					if(nameSplits.length == 2) {
						if(performDoubleResolving(myCard, nameSplits[0], nameSplits[1]) == false)
							performDoubleResolving(myCard, nameSplits[1], nameSplits[0]);
						continue;
					}					
					
					/**
					 * pattern: prename | lastname
					 */
					performSingleResolving(myCard, mailAccountName, true);
					
				}
				
			}
			
		}
		
	}	
	
	public boolean performSingleResolving(VCardWrapper card, String email, boolean allowStringEditDistForPrename) {
		
		email = email.toLowerCase();
				
		/**
		 * check if mail accountname is a prename
		 */
		if(card.existsPreName() == false) {
			if(this.prenames.containsKey(email)) {
				card.setPreName(email);
				log.info("++++++++++ resolved prename from email: (" + card.getEmail() + " -> " + email
						+ ") ++++++++++");				
				return true;
			}
			
			/**
			 * no exact match, try levenshtein distance
			 */
			if(allowStringEditDistForPrename) {
				Iterator iter = this.prenames.keySet().iterator();
				while(iter.hasNext()) {
									
					String cEntry = (String) iter.next();
					if(LevenshteinDistance.LD(email, cEntry) <= this.maxLevenshteinDistanceForPrename) {
						/**
						 * levenshtein distance is small enough for a match
						 */
						card.setPreName(cEntry);
						log.info("++++++++++ resolved prename from email: (" + card.getEmail() + " -> " + cEntry
								+ ") ++++++++++");
						return true;
					}
					
				}
			}
		}
		
		/**
		 * check if mail accountname is a name
		 */
		if(card.existsLastName() == false) {
			if(this.names.containsKey(email)) {
				card.setLastName(email);
				log.info("++++++++++ resolved lastname from email: (" + card.getEmail() + " -> " + email
						+ ") ++++++++++");						
				return true;
			}
		}
		
		return false;
		
	}
	
	public boolean performDoubleResolving(VCardWrapper card, String emailPart1, String emailPart2) {
		
		emailPart1 = emailPart1.toLowerCase();
		emailPart2 = emailPart2.toLowerCase();
		
		boolean success = false;
		
		if(performSingleResolving(card, emailPart1, false)) success = true;
		if(performSingleResolving(card, emailPart2, false)) success = true;
		
		if(card.existsPreName() == false || card.existsLastName() == false) {
			
			if(card.existsPreName() && card.existsLastName() == false) {
				if(card.getPreName().compareTo(emailPart1) == 0) {
					card.setLastName(emailPart2);
				} else {
					card.setLastName(emailPart1);
				}
			} else if(card.existsPreName() == false && card.existsLastName()) {
				if(card.getLastName().compareTo(emailPart1) == 0) {
					card.setPreName(emailPart2);
				} else {
					card.setPreName(emailPart1);
				}
			}
			
		}
		
		return success;
		
	}
	
}